package com.lock;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.List;

/**
 * @author:wesley
 */
public class DistributedLock {

    private ZooKeeper zk;

    //自己的路径，和waitPath做对比 ，要是最小的路径 ，那么就排在第一个
    private String selfPath = "";

    //等待目录
    private String waitPath = "";

    //组目录
    private String groupPath = "/disLocks";

    //子目录
    private String subPath = "/disLocks/sub";


    private String log_prefix = Thread.currentThread().getName();

    private Logger logger = LoggerFactory.getLogger(DistributedLock.class);


    private Watcher watcher;

    public void setWatcher(Watcher watcher) {
        this.watcher = watcher;
    }

    public Watcher getWatcher() {
        return watcher;
    }

    public DistributedLock(ZooKeeper zk) {
        this.zk = zk;
    }


    /**
     *
     * 获取锁分布式的锁
     *
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    public boolean getLock() throws KeeperException, InterruptedException {
        //先创建一个路径 ，带有序列号 例如：/disLocks/sub000000001;
        selfPath = zk.create(subPath,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        logger.info(log_prefix + "创建了"+selfPath+"节点");

        //检测是不是最小节点
        if (checkMinPath()){
            return true;
        }
        return false;
    }


    /**
     *
     * @param path
     * @param data
     * @return
     */
    public boolean createGroupNode(String path , String data) throws KeeperException, InterruptedException {
        if (zk.exists(path,false) == null) {
            //创建一个持久化的节点
            String url = zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            logger.info(log_prefix + "创建了一个节点,"+url +", data : "+data);
        }
        return true;
    }



    public void  unlock(){
        try {
            if (zk.exists(this.selfPath , false) == null) {
                logger.info(log_prefix + "节点已经不存在了。。。。。");
                return;
            }
            zk.delete(selfPath, -1);
            logger.info(log_prefix +" 删除节点： "+selfPath+"下一个:"+waitPath);
            zk.close();
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }



    public boolean checkMinPath() throws KeeperException, InterruptedException {
        List<String> subNodes = zk.getChildren(groupPath,false);
        Collections.sort(subNodes);

        //提取子节点的位置索引,sub00000001


        System.out.println("selfPath" + selfPath);

        int index = subNodes.indexOf(selfPath.substring(groupPath.length() + 1));


        if (index < 0) {
            //不存在
            logger.info(log_prefix + "节点不存在 -----> "+selfPath);
            return false;
        } else if (index == 0) {
            //存在，而且位置是第一个
            logger.info(log_prefix + "排在第一个 -----> "+selfPath);
            return true;
        } else {
            //存在，但是位置比较靠后
            //获取之前的位置的路径
            this.waitPath =groupPath +"/" +subNodes.get(index -1);
            logger.info(log_prefix + "获取子节点，排在我前面的"+waitPath);

            try {
                zk.getData(waitPath,this.watcher,new Stat());
                return false;
            }catch (KeeperException e){
                if (zk.exists(waitPath,false) == null) {
                    logger.info(log_prefix+"子节点中，排在我前面的"+waitPath+"已失踪，幸福来得太突然?");
                    return checkMinPath();
                } else {
                    throw e;
                }
            }
        }
    }


    public String getWaitPath() {
        return waitPath;
    }

    public void setWaitPath(String waitPath) {
        this.waitPath = waitPath;
    }
}
